"""
用户服务层
处理用户相关的业务逻辑
"""
from typing import Dict, Any, Optional, Tuple, List
from fastapi import HTTPException, status

from apps.auth.models.user import User
from apps.auth.repositories.user_repository import UserRepository
from pkg.common.constants.auth import UserStatusInt
from pkg.common.constants.response import ResponseCode


class UserService:
    """用户服务类"""

    @staticmethod
    async def create_user(user_data: Dict[str, Any]) -> User:
        """
        创建用户
        :param user_data: 用户数据
        :return: 创建的用户实例
        :raises: HTTPException 如果用户名或邮箱已存在
        """
        # 检查用户名是否存在
        if await UserRepository.exists_by_username(user_data["username"]):
            raise HTTPException(
                status_code=status.HTTP_409_CONFLICT,
                detail="用户名已存在"
            )

        # 检查邮箱是否存在
        if await UserRepository.exists_by_email(user_data["email"]):
            raise HTTPException(
                status_code=status.HTTP_409_CONFLICT,
                detail="邮箱已存在"
            )

        # 创建用户对象并设置密码
        # 复制用户数据字典以避免修改原始字典
        user_data_copy = user_data.copy()
        plain_password = user_data_copy.pop("password", None)

        # 首先创建用户并保存密码哈希值
        from apps.auth.models.user import pwd_context

        # 确保密码字段不为空
        if plain_password:
            user_data_copy["password"] = pwd_context.hash(plain_password)
        else:
            raise HTTPException(
                status_code=status.HTTP_400_BAD_REQUEST,
                detail="密码不能为空"
            )

        # 创建用户实例
        user = await UserRepository.create(user_data_copy)

        return user

    @staticmethod
    async def get_user_by_id(user_id: int) -> User:
        """
        通过ID获取用户
        :param user_id: 用户ID
        :return: 用户实例
        :raises: HTTPException 如果用户不存在
        """
        user = await UserRepository.get_by_id(user_id)
        if not user:
            raise HTTPException(
                status_code=status.HTTP_400_BAD_REQUEST,
                detail=f"ID为{user_id}的用户不存在"
            )
        return user

    @staticmethod
    async def list_users(
            page: int = 1,
            page_size: int = 10,
            search: Optional[str] = None,
            status: Optional[int] = None,
            role: Optional[str] = None
    ) -> Tuple[List[User], int]:
        """
        获取用户列表
        :param page: 页码
        :param page_size: 每页大小
        :param search: 搜索关键词
        :param status: 用户状态过滤
        :param role: 用户角色过滤
        :return: 用户列表和总数
        """
        return await UserRepository.list_users(page, page_size, search, status, role)

    @staticmethod
    async def update_user(user_id: int, update_data: Dict[str, Any]) -> User:
        """
        更新用户信息(部分更新)
        :param user_id: 用户ID
        :param update_data: 更新数据
        :return: 更新后的用户
        :raises: HTTPException 如果用户不存在或用户名/邮箱冲突
        """
        # 获取用户
        user = await UserService.get_user_by_id(user_id)

        # 检查用户名是否已存在
        if "username" in update_data and update_data["username"] != user.username:
            if await UserRepository.exists_by_username(update_data["username"]):
                raise HTTPException(
                    status_code=status.HTTP_409_CONFLICT,
                    detail="用户名已存在"
                )

        # 检查邮箱是否已存在
        if "email" in update_data and update_data["email"] != user.email:
            if await UserRepository.exists_by_email(update_data["email"]):
                raise HTTPException(
                    status_code=status.HTTP_409_CONFLICT,
                    detail="邮箱已存在"
                )

        # 更新用户
        updated_user = await UserRepository.update(user, update_data)

        return updated_user

    @staticmethod
    async def update_user_whole(user_id: int, update_data: Dict[str, Any]) -> User:
        """
        全量更新用户信息
        :param user_id: 用户ID
        :param update_data: 完整更新数据
        :return: 更新后的用户
        :raises: HTTPException 如果用户不存在或用户名/邮箱冲突
        """
        # 获取用户
        user = await UserService.get_user_by_id(user_id)

        # 检查用户名是否已存在
        if update_data["username"] != user.username:
            if await UserRepository.exists_by_username(update_data["username"]):
                raise HTTPException(
                    status_code=status.HTTP_409_CONFLICT,
                    detail="用户名已存在"
                )

        # 检查邮箱是否已存在
        if update_data["email"] != user.email:
            if await UserRepository.exists_by_email(update_data["email"]):
                raise HTTPException(
                    status_code=status.HTTP_409_CONFLICT,
                    detail="邮箱已存在"
                )

        # 全量更新用户
        updated_user = await UserRepository.update_whole(user, update_data)

        return updated_user

    @staticmethod
    async def delete_user(user_id: int) -> None:
        """
        软删除用户
        :param user_id: 用户ID
        :raises: HTTPException 如果用户不存在
        """
        user = await UserService.get_user_by_id(user_id)
        await UserRepository.delete(user)

    @staticmethod
    async def hard_delete_user(user_id: int) -> None:
        """
        硬删除用户
        :param user_id: 用户ID
        :raises: HTTPException 如果用户不存在
        """
        user = await UserService.get_user_by_id(user_id)
        await UserRepository.hard_delete(user)

    @staticmethod
    async def set_user_password(user_id: int, password: str) -> User:
        """
        设置用户密码
        :param user_id: 用户ID
        :param password: 新密码
        :return: 更新后的用户
        :raises: HTTPException 如果用户不存在
        """
        user = await UserService.get_user_by_id(user_id)
        user.set_password(password)
        await user.save()
        return user

    @staticmethod
    async def authenticate_user(username: str, password: str) -> tuple[Optional[User], Optional[str], Optional[int]]:
        """
        验证用户凭据
        :param username: 用户名
        :param password: 密码
        :return: 三元组 (用户对象, 错误消息, 错误码)
                 - 验证成功: (用户对象, None, None)
                 - 验证失败: (None, 错误消息, 错误码)
        """
        # 获取用户
        user = await UserRepository.get_by_username(username)
        if not user:
            return None, "用户不存在", ResponseCode.NOT_FOUND

        # 检查密码
        from apps.auth.models.user import pwd_context
        if not pwd_context.verify(password, user.password):
            return None, "密码错误", ResponseCode.UNAUTHORIZED

        # 检查用户状态
        if user.status != UserStatusInt.ACTIVE:
            # 根据不同的状态返回相应的错误消息
            if user.status == UserStatusInt.INACTIVE:
                return None, "用户已禁用，请联系管理员", ResponseCode.FORBIDDEN
            elif user.status == UserStatusInt.LOCKED:
                return None, "用户已锁定，请稍后再试", ResponseCode.FORBIDDEN
            else:
                return None, "用户状态异常，请联系管理员", ResponseCode.FORBIDDEN

        return user, None, None

    @staticmethod
    async def update_last_login(user_id: int) -> User:
        """
        更新用户最后登录时间
        :param user_id: 用户ID
        :return: 更新后的用户
        """
        from datetime import datetime, timezone

        user = await UserService.get_user_by_id(user_id)
        user.last_login = datetime.now(timezone.utc)
        await user.save()
        return user
